/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.filesystems;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.io.*;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.util.NbBundle;
import org.openide.util.actions.SystemAction;
import org.openide.util.enum.SingletonEnumeration;
import org.openide.util.enum.SequenceEnumeration;
/** Local file system. Provides access to files on local disk.
*/
public class LocalFileSystem extends AbstractFileSystem
implements AbstractFileSystem.List, AbstractFileSystem.Info,
AbstractFileSystem.Change {
/** generated Serialized Version UID */
static final long serialVersionUID = -5355566113542272442L;
/** refresh time (30s) */
private static final int REFRESH_TIME = 15000;
/** root file */
private File rootFile = new File ("."); // NOI18N
/** is read only */
private boolean readOnly;
/** Constructor.
*/
public LocalFileSystem () {
info = this;
change = this;
DefaultAttributes a = new DefaultAttributes (info, change, this);
attr = a;
list = a;
setRefreshTime (REFRESH_TIME);
}
/** Constructor. Allows user to provide own capabilities
* for this file system.
* @param cap capabilities for this file system
*/
public LocalFileSystem (FileSystemCapability cap) {
this ();
setCapability (cap);
}
/* Human presentable name */
public String getDisplayName() {
if(!isValid())
return getString("LAB_FileSystemInvalid", rootFile.toString ());
else
return getString ("LAB_FileSystemValid", rootFile.toString ());
}
/** Set the root directory of the file system.
* @param r file to set root to
* @exception PropertyVetoException if the value if vetoed by someone else (usually
* by the {@link org.openide.filesystems.Repository Repository})
* @exception IOException if the root does not exists or some other error occured
*/
public synchronized void setRootDirectory (File r) throws PropertyVetoException, IOException {
if (!r.exists() || r.isFile ()) {
FSException.io ("EXC_RootNotExist", r.toString ()); // NOI18N
}
setSystemName(computeSystemName (r));
rootFile = r;
firePropertyChange("root", null, refreshRoot ()); // NOI18N
}
/** Get the root directory of the file system.
* @return root directory
*/
public File getRootDirectory () {
return rootFile;
}
/** Set whether the file system should be read only.
* @param flag <code>true</code> if it should
*/
public void setReadOnly(boolean flag) {
if (flag != readOnly) {
readOnly = flag;
firePropertyChange (PROP_READ_ONLY, new Boolean (!flag), new Boolean (flag));
}
}
/* Test whether file system is read only.
* @return <true> if file system is read only
*/
public boolean isReadOnly() {
return readOnly;
}
/** Prepare environment by adding the root directory of the file system to the class path.
* @param environment the environment to add to
*/
public void prepareEnvironment(FileSystem.Environment environment) {
environment.addClassPath(rootFile.toString ());
}
/** Compute the system name of this file system for a given root directory.
* <P>
* The default implementation simply returns the filename separated by slashes.
* @see FileSystem#setSystemName
* @param rootFile root directory for the filesystem
* @return system name for the filesystem
*/
protected String computeSystemName (File rootFile) {
return rootFile.toString ().replace(File.separatorChar, '/');
}
/** Creates file for given string name.
* @param name the name
* @return the file
*/
private File getFile (String name) {
return new File (rootFile, name);
}
//
// List
//
/* Scans children for given name
*/
public String[] children (String name) {
File f = getFile (name);
if (f.isDirectory ()) {
return f.list ();
} else {
return null;
}
}
//
// Change
//
/* Creates new folder named name.
* @param name name of folder
* @throws IOException if operation fails
*/
public void createFolder (String name) throws java.io.IOException {
File f = getFile (name);
Object[] errorParams = new Object[] {
f.getName (),
getDisplayName (),
f.toString ()
};
if (name.equals ("")) { // NOI18N
FSException.io ("EXC_CannotCreateF", errorParams); // NOI18N
}
if (f.exists()) {
FSException.io ("EXC_FolderAlreadyExist", errorParams); // NOI18N
}
boolean b = createRecursiveFolder(f);
if (!b) {
FSException.io ("EXC_CannotCreateF", errorParams); // NOI18N
}
}
/** Creates new folder and all necessary subfolders
* @param f folder to create
* @return <code>true</code> if the file exists when returning from this method
*/
private static boolean createRecursiveFolder(File f) {
if (f.exists()) return true;
if (!f.isAbsolute())
f = f.getAbsoluteFile();
String par = f.getParent();
if (par == null) return false;
if (!createRecursiveFolder(new File(par))) return false;
f.mkdir();
return f.exists();
}
/* Create new data file.
*
* @param name name of the file
*
* @return the new data file object
* @exception IOException if the file cannot be created (e.g. already exists)
*/
public void createData (String name) throws IOException {
File f = getFile (name);
Object[] errorParams = new Object[] {
f.getName (),
getDisplayName (),
f.toString (),
};
if (!f.createNewFile ()) {
FSException.io ("EXC_DataAlreadyExist", errorParams); // NOI18N
}
/* JST: Maybe handled by createNewFile, but probably
if (!tmp.exists())
throw new IOException(MessageFormat.format (LocalFileSystem.getString("EXC_CannotCreateD"), errorParams));
*/
}
/* Renames a file.
*
* @param oldName old name of the file
* @param newName new name of the file
*/
public void rename(String oldName, String newName) throws IOException {
File of = getFile (oldName);
File nf = getFile (newName);
if (nf.exists() || !of.renameTo (nf)) {
FSException.io ("EXC_CannotRename", oldName, getDisplayName (), newName); // NOI18N
}
}
/* Delete the file.
*
* @param name name of file
* @exception IOException if the file could not be deleted
*/
public void delete (String name) throws IOException {
File file = getFile (name);
if (file.exists()) {
if (!deleteFile (file)) {
FSException.io ("EXC_CannotDelete", name, getDisplayName (), file.toString ()); // NOI18N
}
}
}
/** Method that recursivelly deletes all files in a folder.
* @return true if successful
*/
private static boolean deleteFile (File file) {
if (file.isDirectory()) {
// first of all delete whole content
File[] arr = file.listFiles();
for (int i = 0; i < arr.length; i++) {
if (!deleteFile (arr[i])) {
return false;
}
}
}
// delete the file itself
return file.delete();
}
//
// Info
//
/*
* Get last modification time.
* @param name the file to test
* @return the date
*/
public java.util.Date lastModified(String name) {
return new java.util.Date (getFile (name).lastModified ());
}
/* Test if the file is folder or contains data.
* @param name name of the file
* @return true if the file is folder, false otherwise
*/
public boolean folder (String name) {
return getFile (name).isDirectory ();
}
/* Test whether this file can be written to or not.
* @param name the file to test
* @return <CODE>true</CODE> if file is read-only
*/
public boolean readOnly (String name) {
File f = getFile (name);
return !f.canWrite () && f.exists ();
}
/** Get the MIME type of the file.
* Uses {@link FileUtil#getMIMEType}.
*
* @param name the file to test
* @return the MIME type textual representation, e.g. <code>"text/plain"</code>
*/
public String mimeType (String name) {
int i = name.lastIndexOf ('.');
String s;
try {
s = FileUtil.getMIMEType (name.substring (i + 1));
} catch (IndexOutOfBoundsException e) {
s = null;
}
return s == null ? "content/unknown" : s; // NOI18N
}
/** Get the size of the file.
*
* @param name the file to test
* @return the size of the file in bytes or zero if the file does not contain data (does not
* exist or is a folder).
*/
public long size (String name) {
return getFile (name).length ();
}
// ===============================================================================
// This part of code could be used for monitoring of closing file streams.
/* public static java.util.HashMap openedIS = new java.util.HashMap();
public static java.util.HashMap openedOS = new java.util.HashMap();
static class DebugIS extends FileInputStream {
public DebugIS(File f) throws java.io.FileNotFoundException { super(f); }
public void close() throws IOException { openedIS.remove(this); super.close(); }
};
static class DebugOS extends FileOutputStream {
public DebugOS(File f) throws java.io.IOException { super(f); }
public void close() throws IOException { openedOS.remove(this); super.close(); }
};
public InputStream inputStream (String name) throws java.io.FileNotFoundException {
DebugIS is = new DebugIS(getFile(name));
openedIS.put(is, new Exception());
return is;
}
public OutputStream outputStream (String name) throws java.io.IOException {
DebugOS os = new DebugOS(getFile(name));
openedOS.put(os, new Exception());
return os;
}*/
// End of the debug part
// ============================================================================
// Begin of the original part
/** Get input stream.
*
* @param name the file to test
* @return an input stream to read the contents of this file
* @exception FileNotFoundException if the file does not exists or is invalid
*/
public InputStream inputStream (String name) throws java.io.FileNotFoundException {
return new FileInputStream(getFile(name));
}
/** Get output stream.
*
* @param name the file to test
* @return output stream to overwrite the contents of this file
* @exception IOException if an error occures (the file is invalid, etc.)
*/
public OutputStream outputStream (String name) throws java.io.IOException {
return new FileOutputStream (getFile (name));
}
// End of the original part
// ============================================================================
/** Does nothing to lock the file.
*
* @param name name of the file
*/
public void lock (String name) throws IOException {
File file = getFile (name);
if (file.exists () && !file.canWrite ()) {
FSException.io ("EXC_CannotLock", name, getDisplayName (), file.toString ()); // NOI18N
}
}
/** Does nothing to unlock the file.
*
* @param name name of the file
*/
public void unlock (String name) {
}
/** Does nothing to mark the file as unimportant.
*
* @param name the file to mark
*/
public void markUnimportant (String name) {
}
/* JST: Commented out, only testing examples for Q&A
//
// Testing routines
//
private static void out (FileObject fo, boolean ref, boolean rec) {
if (ref) fo.refresh ();
Enumeration en = fo.getChildren (rec);
while (en.hasMoreElements ()) {
FileObject f = (FileObject)en.nextElement ();
if (ref) f.refresh ();
System.out.println (f + " size: " + f.getSize ());
}
}
// Cyclic test for external modifications
private static void cycle (FileObject fo) throws Exception {
int x = '\n';
boolean ref = false;
for (;;) {
if (x == '\n') out (fo, ref, true);
x = System.in.read ();
ref = true;
}
}
// Create new file test
private static void createData (FileObject fo, String name, String ext) throws Exception {
out (fo, false, false);
System.out.println ("----------");
FileObject nf = fo.createData (name, ext);
out (fo, false, false);
System.out.println ("---------- the object: " + nf);
fo.refresh ();
out (fo, false, false);
System.out.println ("---------- end");
}
// Create new folder test
private static void createFolder (FileObject fo, String name) throws Exception {
out (fo, false, false);
System.out.println ("----------");
FileObject nf = fo.createFolder (name);
out (fo, false, false);
System.out.println ("---------- the object: " + nf);
fo.refresh ();
out (fo, false, false);
System.out.println ("---------- end");
}
// Delete
private static void delete (FileObject fo) throws Exception {
out (fo.getParent (), false, false);
System.out.println ("----------");
FileLock l = fo.lock ();
fo.delete (l);
l.releaseLock ();
out (fo.getParent (), false, false);
System.out.println ("---------- the object: " + fo + " is valid: " + fo.isValid ());
fo.getParent ().refresh ();
out (fo.getParent (), false, false);
System.out.println ("---------- end");
}
public static void main (String[] args) throws Exception {
LocalFileSystem fs = new LocalFileSystem ();
fs.setRootDirectory (new File (args[0]));
FileObject fo = fs.getRoot ();
// cycle (fo);
// createData (fo, args[1], args[2]);
// createFolder (fo, args[1]);
delete (fs.findResource (args[1]));
}
*/
}
/*
* Log
* 18 Gandalf-post-FCS1.16.1.0 3/24/00 Svatopluk Dedic Workaround for bug in
* JDK's File.renameTo; existing destination was overwritten on UNIXes,
* preserved on Windows.
* 17 src-jtulach1.16 1/12/00 Ian Formanek NOI18N
* 16 src-jtulach1.15 1/4/00 Petr Jiricka Fix for a subtle bug:
* when the root directory of the filesystem does not exist,
* createFolder() did not work.
* 15 src-jtulach1.14 12/30/99 Jaroslav Tulach New dialog for
* notification of exceptions.
* 14 src-jtulach1.13 12/6/99 Jaroslav Tulach #2313
* 13 src-jtulach1.12 10/29/99 Jaroslav Tulach MultiFileSystem +
* FileStatusEvent
* 12 src-jtulach1.11 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 11 src-jtulach1.10 10/8/99 Petr Hamernik debug methods for
* closing streams was added and commented (could be useful in the future)
* 10 src-jtulach1.9 10/6/99 Jaroslav Tulach Cannot lock readonly
* files.
* 9 src-jtulach1.8 10/6/99 Ales Novak bugfix #4076 and #3617
* 8 src-jtulach1.7 6/10/99 Jaroslav Tulach Capabilities can be
* passed to constructor.
* 7 src-jtulach1.6 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 6 src-jtulach1.5 4/6/99 Ian Formanek Imporved error messages
* 5 src-jtulach1.4 3/31/99 Ian Formanek Fixed order of
* parameters for error message DataAlreadyExists
* 4 src-jtulach1.3 3/26/99 Jesse Glick [JavaDoc]
* 3 src-jtulach1.2 3/26/99 Jaroslav Tulach Refresh & Bundles
* 2 src-jtulach1.1 3/26/99 Jaroslav Tulach
* 1 src-jtulach1.0 3/24/99 Jaroslav Tulach
* $
*/